static int read_any(
unsigned long addr,
unsigned long *val,
- unsigned int bytes)
+ unsigned int bytes,
+ struct x86_emulate_ctxt *ctxt)
{
switch ( bytes )
{
static int write_any(
unsigned long addr,
unsigned long val,
- unsigned int bytes)
+ unsigned int bytes,
+ struct x86_emulate_ctxt *ctxt)
{
switch ( bytes )
{
unsigned long addr,
unsigned long old,
unsigned long new,
- unsigned int bytes)
+ unsigned int bytes,
+ struct x86_emulate_ctxt *ctxt)
{
switch ( bytes )
{
unsigned long old_lo,
unsigned long old_hi,
unsigned long new_lo,
- unsigned long new_hi)
+ unsigned long new_hi,
+ struct x86_emulate_ctxt *ctxt)
{
((unsigned long *)addr)[0] = new_lo;
((unsigned long *)addr)[1] = new_hi;
return X86EMUL_CONTINUE;
}
-static struct x86_mem_emulator emulops = {
+static struct x86_emulate_ops emulops = {
read_any, write_any, read_any, write_any, cmpxchg_any, cmpxchg8b_any
};
int main(int argc, char **argv)
{
+ struct x86_emulate_ctxt ctxt;
struct cpu_user_regs regs;
char instr[20] = { 0x01, 0x08 }; /* add %ecx,(%eax) */
unsigned int res = 0x7FFFFFFF;
u32 cmpxchg8b_res[2] = { 0x12345678, 0x87654321 };
- unsigned long cr2;
int rc;
+ ctxt.regs = ®s;
+ ctxt.mode = X86EMUL_MODE_PROT32;
+
printf("%-40s", "Testing addl %%ecx,(%%eax)...");
instr[0] = 0x01; instr[1] = 0x08;
regs.eflags = 0x200;
regs.eip = (unsigned long)&instr[0];
regs.ecx = 0x12345678;
- cr2 = (unsigned long)&res;
+ ctxt.cr2 = (unsigned long)&res;
res = 0x7FFFFFFF;
- rc = x86_emulate_memop(®s, cr2, &emulops, X86EMUL_MODE_PROT32);
+ rc = x86_emulate_memop(&ctxt, &emulops);
if ( (rc != 0) ||
(res != 0x92345677) ||
(regs.eflags != 0xa94) ||
#else
regs.ecx = 0x12345678UL;
#endif
- cr2 = (unsigned long)&res;
- rc = x86_emulate_memop(®s, cr2, &emulops, X86EMUL_MODE_PROT32);
+ ctxt.cr2 = (unsigned long)&res;
+ rc = x86_emulate_memop(&ctxt, &emulops);
if ( (rc != 0) ||
(res != 0x92345677) ||
(regs.ecx != 0x8000000FUL) ||
regs.eip = (unsigned long)&instr[0];
regs.eax = 0x92345677UL;
regs.ecx = 0xAA;
- cr2 = (unsigned long)&res;
- rc = x86_emulate_memop(®s, cr2, &emulops, X86EMUL_MODE_PROT32);
+ ctxt.cr2 = (unsigned long)&res;
+ rc = x86_emulate_memop(&ctxt, &emulops);
if ( (rc != 0) ||
(res != 0x923456AA) ||
(regs.eflags != 0x244) ||
regs.eip = (unsigned long)&instr[0];
regs.eax = 0xAABBCC77UL;
regs.ecx = 0xFF;
- cr2 = (unsigned long)&res;
- rc = x86_emulate_memop(®s, cr2, &emulops, X86EMUL_MODE_PROT32);
+ ctxt.cr2 = (unsigned long)&res;
+ rc = x86_emulate_memop(&ctxt, &emulops);
if ( (rc != 0) ||
(res != 0x923456AA) ||
((regs.eflags&0x240) != 0x200) ||
regs.eflags = 0x200;
regs.eip = (unsigned long)&instr[0];
regs.ecx = 0x12345678;
- cr2 = (unsigned long)&res;
- rc = x86_emulate_memop(®s, cr2, &emulops, X86EMUL_MODE_PROT32);
+ ctxt.cr2 = (unsigned long)&res;
+ rc = x86_emulate_memop(&ctxt, &emulops);
if ( (rc != 0) ||
(res != 0x12345678) ||
(regs.eflags != 0x200) ||
regs.eip = (unsigned long)&instr[0];
regs.eax = 0x923456AAUL;
regs.ecx = 0xDDEEFF00L;
- cr2 = (unsigned long)&res;
- rc = x86_emulate_memop(®s, cr2, &emulops, X86EMUL_MODE_PROT32);
+ ctxt.cr2 = (unsigned long)&res;
+ rc = x86_emulate_memop(&ctxt, &emulops);
if ( (rc != 0) ||
(res != 0xDDEEFF00) ||
(regs.eflags != 0x244) ||
regs.esi = (unsigned long)&res + 0;
regs.edi = (unsigned long)&res + 2;
regs.error_code = 0; /* read fault */
- cr2 = regs.esi;
- rc = x86_emulate_memop(®s, cr2, &emulops, X86EMUL_MODE_PROT32);
+ ctxt.cr2 = regs.esi;
+ rc = x86_emulate_memop(&ctxt, &emulops);
if ( (rc != 0) ||
(res != 0x44554455) ||
(regs.eflags != 0x200) ||
regs.eflags = 0x200;
regs.eip = (unsigned long)&instr[0];
regs.edi = (unsigned long)&res;
- cr2 = regs.edi;
- rc = x86_emulate_memop(®s, cr2, &emulops, X86EMUL_MODE_PROT32);
+ ctxt.cr2 = regs.edi;
+ rc = x86_emulate_memop(&ctxt, &emulops);
if ( (rc != 0) ||
(res != 0x2233445D) ||
((regs.eflags&0x201) != 0x201) ||
regs.ecx = 0xCCCCFFFF;
regs.eip = (unsigned long)&instr[0];
regs.edi = (unsigned long)cmpxchg8b_res;
- cr2 = regs.edi;
- rc = x86_emulate_memop(®s, cr2, &emulops, X86EMUL_MODE_PROT32);
+ ctxt.cr2 = regs.edi;
+ rc = x86_emulate_memop(&ctxt, &emulops);
if ( (rc != 0) ||
(cmpxchg8b_res[0] != 0x9999AAAA) ||
(cmpxchg8b_res[1] != 0xCCCCFFFF) ||
instr[0] = 0x0f; instr[1] = 0xc7; instr[2] = 0x0f;
regs.eip = (unsigned long)&instr[0];
regs.edi = (unsigned long)cmpxchg8b_res;
- cr2 = regs.edi;
- rc = x86_emulate_memop(®s, cr2, &emulops, X86EMUL_MODE_PROT32);
+ ctxt.cr2 = regs.edi;
+ rc = x86_emulate_memop(&ctxt, &emulops);
if ( (rc != 0) ||
(cmpxchg8b_res[0] != 0x9999AAAA) ||
(cmpxchg8b_res[1] != 0xCCCCFFFF) ||
instr[0] = 0x0f; instr[1] = 0xbe; instr[2] = 0x08;
regs.eip = (unsigned long)&instr[0];
regs.ecx = 0x12345678;
- cr2 = (unsigned long)&res;
+ ctxt.cr2 = (unsigned long)&res;
res = 0x82;
- rc = x86_emulate_memop(®s, cr2, &emulops, X86EMUL_MODE_PROT32);
+ rc = x86_emulate_memop(&ctxt, &emulops);
if ( (rc != 0) ||
(res != 0x82) ||
(regs.ecx != 0xFFFFFF82) ||
instr[0] = 0x0f; instr[1] = 0xb7; instr[2] = 0x08;
regs.eip = (unsigned long)&instr[0];
regs.ecx = 0x12345678;
- cr2 = (unsigned long)&res;
+ ctxt.cr2 = (unsigned long)&res;
res = 0x1234aa82;
- rc = x86_emulate_memop(®s, cr2, &emulops, X86EMUL_MODE_PROT32);
+ rc = x86_emulate_memop(&ctxt, &emulops);
if ( (rc != 0) ||
(res != 0x1234aa82) ||
(regs.ecx != 0xaa82) ||
/* Turn a sub-word access into a full-word access. */
if ( bytes != sizeof(paddr_t) )
{
- int rc;
- paddr_t full;
- unsigned int offset = addr & (sizeof(paddr_t)-1);
+ paddr_t full;
+ unsigned int offset = addr & (sizeof(paddr_t)-1);
/* Align address; read full word. */
addr &= ~(sizeof(paddr_t)-1);
- if ( (rc = x86_emulate_read_std(addr, (unsigned long *)&full,
- sizeof(paddr_t))) )
- return rc;
+ if ( copy_from_user(&full, (void *)addr, sizeof(paddr_t)) )
+ {
+ propagate_page_fault(addr, 4); /* user mode, read fault */
+ return X86EMUL_PROPAGATE_FAULT;
+ }
/* Mask out bits provided by caller. */
full &= ~((((paddr_t)1 << (bytes*8)) - 1) << (offset*8));
/* Shift the caller value and OR in the missing bits. */
static int ptwr_emulated_write(
unsigned long addr,
unsigned long val,
- unsigned int bytes)
+ unsigned int bytes,
+ struct x86_emulate_ctxt *ctxt)
{
return ptwr_emulated_update(addr, 0, val, bytes, 0);
}
unsigned long addr,
unsigned long old,
unsigned long new,
- unsigned int bytes)
+ unsigned int bytes,
+ struct x86_emulate_ctxt *ctxt)
{
return ptwr_emulated_update(addr, old, new, bytes, 1);
}
unsigned long old,
unsigned long old_hi,
unsigned long new,
- unsigned long new_hi)
+ unsigned long new_hi,
+ struct x86_emulate_ctxt *ctxt)
{
if ( CONFIG_PAGING_LEVELS == 2 )
return X86EMUL_UNHANDLEABLE;
addr, ((u64)old_hi << 32) | old, ((u64)new_hi << 32) | new, 8, 1);
}
-static struct x86_mem_emulator ptwr_mem_emulator = {
+static struct x86_emulate_ops ptwr_emulate_ops = {
.read_std = x86_emulate_read_std,
.write_std = x86_emulate_write_std,
.read_emulated = x86_emulate_read_std,
l2_pgentry_t *pl2e, l2e;
int which, flags;
unsigned long l2_idx;
+ struct x86_emulate_ctxt emul_ctxt;
if ( unlikely(shadow_mode_enabled(d)) )
return 0;
return EXCRET_fault_fixed;
emulate:
- if ( x86_emulate_memop(guest_cpu_user_regs(), addr,
- &ptwr_mem_emulator, X86EMUL_MODE_HOST) )
+ emul_ctxt.regs = guest_cpu_user_regs();
+ emul_ctxt.cr2 = addr;
+ emul_ctxt.mode = X86EMUL_MODE_HOST;
+ if ( x86_emulate_memop(&emul_ctxt, &ptwr_emulate_ops) )
return 0;
perfc_incrc(ptwr_emulations);
return EXCRET_fault_fixed;
#endif /* __i386__ */
/* Fetch next part of the instruction being emulated. */
-#define insn_fetch(_type, _size, _eip) \
-({ unsigned long _x; \
- if ( (rc = ops->read_std((unsigned long)(_eip), &_x, (_size))) != 0 ) \
- goto done; \
- (_eip) += (_size); \
- (_type)_x; \
+#define insn_fetch(_type, _size, _eip) \
+({ unsigned long _x; \
+ rc = ops->read_std((unsigned long)(_eip), &_x, (_size), ctxt); \
+ if ( rc != 0 ) \
+ goto done; \
+ (_eip) += (_size); \
+ (_type)_x; \
})
/* Access/update address held in a register, based on addressing mode. */
return p;
}
-int
+int
x86_emulate_memop(
- struct cpu_user_regs *regs,
- unsigned long cr2,
- struct x86_mem_emulator *ops,
- int mode)
+ struct x86_emulate_ctxt *ctxt,
+ struct x86_emulate_ops *ops)
{
uint8_t b, d, sib, twobyte = 0, rex_prefix = 0;
uint8_t modrm, modrm_mod = 0, modrm_reg = 0, modrm_rm = 0;
unsigned int op_bytes, ad_bytes, lock_prefix = 0, rep_prefix = 0, i;
int rc = 0;
struct operand src, dst;
+ unsigned long cr2 = ctxt->cr2;
+ int mode = ctxt->mode;
/* Shadow copy of register state. Committed on successful emulation. */
- struct cpu_user_regs _regs = *regs;
+ struct cpu_user_regs _regs = *ctxt->regs;
switch ( mode )
{
dst.bytes = (d & ByteOp) ? 1 : op_bytes;
if ( !(d & Mov) && /* optimisation - avoid slow emulated read */
((rc = ops->read_emulated((unsigned long)dst.ptr,
- &dst.val, dst.bytes)) != 0) )
+ &dst.val, dst.bytes, ctxt)) != 0) )
goto done;
break;
}
src.type = OP_MEM;
src.ptr = (unsigned long *)cr2;
if ( (rc = ops->read_emulated((unsigned long)src.ptr,
- &src.val, src.bytes)) != 0 )
+ &src.val, src.bytes, ctxt)) != 0 )
goto done;
src.orig_val = src.val;
break;
if ( mode == X86EMUL_MODE_PROT64 )
dst.bytes = 8;
if ( (rc = ops->read_std(register_address(_regs.ss, _regs.esp),
- &dst.val, dst.bytes)) != 0 )
+ &dst.val, dst.bytes, ctxt)) != 0 )
goto done;
register_address_increment(_regs.esp, dst.bytes);
break;
{
dst.bytes = 8;
if ( (rc = ops->read_std((unsigned long)dst.ptr,
- &dst.val, 8)) != 0 )
+ &dst.val, 8, ctxt)) != 0 )
goto done;
}
register_address_increment(_regs.esp, -dst.bytes);
if ( (rc = ops->write_std(register_address(_regs.ss, _regs.esp),
- dst.val, dst.bytes)) != 0 )
+ dst.val, dst.bytes, ctxt)) != 0 )
goto done;
dst.val = dst.orig_val; /* skanky: disable writeback */
break;
case OP_MEM:
if ( lock_prefix )
rc = ops->cmpxchg_emulated(
- (unsigned long)dst.ptr, dst.orig_val, dst.val, dst.bytes);
+ (unsigned long)dst.ptr, dst.orig_val,
+ dst.val, dst.bytes, ctxt);
else
rc = ops->write_emulated(
- (unsigned long)dst.ptr, dst.val, dst.bytes);
+ (unsigned long)dst.ptr, dst.val, dst.bytes, ctxt);
if ( rc != 0 )
goto done;
default:
}
/* Commit shadow register state. */
- *regs = _regs;
+ *ctxt->regs = _regs;
done:
return (rc == X86EMUL_UNHANDLEABLE) ? -1 : 0;
{
if ( _regs.ecx == 0 )
{
- regs->eip = _regs.eip;
+ ctxt->regs->eip = _regs.eip;
goto done;
}
_regs.ecx--;
- _regs.eip = regs->eip;
+ _regs.eip = ctxt->regs->eip;
}
switch ( b )
{
dst.ptr = (unsigned long *)cr2;
if ( (rc = ops->read_std(register_address(seg ? *seg : _regs.ds,
_regs.esi),
- &dst.val, dst.bytes)) != 0 )
+ &dst.val, dst.bytes, ctxt)) != 0 )
goto done;
}
else
{
/* Read fault: source is special memory. */
dst.ptr = (unsigned long *)register_address(_regs.es, _regs.edi);
- if ( (rc = ops->read_emulated(cr2, &dst.val, dst.bytes)) != 0 )
+ if ( (rc = ops->read_emulated(cr2, &dst.val,
+ dst.bytes, ctxt)) != 0 )
goto done;
}
register_address_increment(
dst.type = OP_REG;
dst.bytes = (d & ByteOp) ? 1 : op_bytes;
dst.ptr = (unsigned long *)&_regs.eax;
- if ( (rc = ops->read_emulated(cr2, &dst.val, dst.bytes)) != 0 )
+ if ( (rc = ops->read_emulated(cr2, &dst.val, dst.bytes, ctxt)) != 0 )
goto done;
register_address_increment(
_regs.esi, (_regs.eflags & EFLG_DF) ? -dst.bytes : dst.bytes);
#if defined(__i386__)
{
unsigned long old_lo, old_hi;
- if ( ((rc = ops->read_emulated(cr2+0, &old_lo, 4)) != 0) ||
- ((rc = ops->read_emulated(cr2+4, &old_hi, 4)) != 0) )
+ if ( ((rc = ops->read_emulated(cr2+0, &old_lo, 4, ctxt)) != 0) ||
+ ((rc = ops->read_emulated(cr2+4, &old_hi, 4, ctxt)) != 0) )
goto done;
if ( (old_lo != _regs.eax) || (old_hi != _regs.edx) )
{
}
else
{
- if ( (rc = ops->cmpxchg8b_emulated(cr2, old_lo, old_hi,
- _regs.ebx, _regs.ecx)) != 0 )
+ if ( (rc = ops->cmpxchg8b_emulated(cr2, old_lo, old_hi, _regs.ebx,
+ _regs.ecx, ctxt)) != 0 )
goto done;
_regs.eflags |= EFLG_ZF;
}
x86_emulate_read_std(
unsigned long addr,
unsigned long *val,
- unsigned int bytes)
+ unsigned int bytes,
+ struct x86_emulate_ctxt *ctxt)
{
*val = 0;
if ( copy_from_user((void *)val, (void *)addr, bytes) )
x86_emulate_write_std(
unsigned long addr,
unsigned long val,
- unsigned int bytes)
+ unsigned int bytes,
+ struct x86_emulate_ctxt *ctxt)
{
if ( copy_to_user((void *)addr, (void *)&val, bytes) )
{
#ifndef __X86_EMULATE_H__
#define __X86_EMULATE_H__
+struct x86_emulate_ctxt;
+
/*
- * x86_mem_emulator:
+ * x86_emulate_ops:
*
* These operations represent the instruction emulator's interface to memory.
* There are two categories of operation: those that act on ordinary memory
#define X86EMUL_PROPAGATE_FAULT 2 /* propagate a generated fault to guest */
#define X86EMUL_RETRY_INSTR 2 /* retry the instruction for some reason */
#define X86EMUL_CMPXCHG_FAILED 2 /* cmpxchg did not see expected value */
-struct x86_mem_emulator
+struct x86_emulate_ops
{
/*
* read_std: Read bytes of standard (non-emulated/special) memory.
int (*read_std)(
unsigned long addr,
unsigned long *val,
- unsigned int bytes);
+ unsigned int bytes,
+ struct x86_emulate_ctxt *ctxt);
/*
* write_std: Write bytes of standard (non-emulated/special) memory.
int (*write_std)(
unsigned long addr,
unsigned long val,
- unsigned int bytes);
+ unsigned int bytes,
+ struct x86_emulate_ctxt *ctxt);
/*
* read_emulated: Read bytes from emulated/special memory area.
int (*read_emulated)(
unsigned long addr,
unsigned long *val,
- unsigned int bytes);
+ unsigned int bytes,
+ struct x86_emulate_ctxt *ctxt);
/*
* write_emulated: Read bytes from emulated/special memory area.
int (*write_emulated)(
unsigned long addr,
unsigned long val,
- unsigned int bytes);
+ unsigned int bytes,
+ struct x86_emulate_ctxt *ctxt);
/*
* cmpxchg_emulated: Emulate an atomic (LOCKed) CMPXCHG operation on an
unsigned long addr,
unsigned long old,
unsigned long new,
- unsigned int bytes);
+ unsigned int bytes,
+ struct x86_emulate_ctxt *ctxt);
/*
- * cmpxchg_emulated: Emulate an atomic (LOCKed) CMPXCHG8B operation on an
- * emulated/special memory area.
+ * cmpxchg8b_emulated: Emulate an atomic (LOCKed) CMPXCHG8B operation on an
+ * emulated/special memory area.
* @addr: [IN ] Linear address to access.
* @old: [IN ] Value expected to be current at @addr.
* @new: [IN ] Value to write to @addr.
unsigned long old_lo,
unsigned long old_hi,
unsigned long new_lo,
- unsigned long new_hi);
+ unsigned long new_hi,
+ struct x86_emulate_ctxt *ctxt);
};
/* Standard reader/writer functions that callers may wish to use. */
x86_emulate_read_std(
unsigned long addr,
unsigned long *val,
- unsigned int bytes);
+ unsigned int bytes,
+ struct x86_emulate_ctxt *ctxt);
extern int
x86_emulate_write_std(
unsigned long addr,
unsigned long val,
- unsigned int bytes);
+ unsigned int bytes,
+ struct x86_emulate_ctxt *ctxt);
struct cpu_user_regs;
+struct x86_emulate_ctxt
+{
+ /* Register state before/after emulation. */
+ struct cpu_user_regs *regs;
+
+ /* Linear faulting address (if emulating a page-faulting instruction). */
+ unsigned long cr2;
+
+ /* Emulated execution mode, represented by an X86EMUL_MODE value. */
+ int mode;
+};
+
/* Execution mode, passed to the emulator. */
#define X86EMUL_MODE_REAL 0 /* Real mode. */
#define X86EMUL_MODE_PROT16 2 /* 16-bit protected mode. */
/*
* x86_emulate_memop: Emulate an instruction that faulted attempting to
* read/write a 'special' memory area.
- * @regs: Register state at time of fault.
- * @cr2: Linear faulting address within an emulated/special memory area.
- * @ops: Interface to access special memory.
- * @mode: Emulated execution mode, represented by an X86EMUL_MODE value.
* Returns -1 on failure, 0 on success.
*/
-extern int
+int
x86_emulate_memop(
- struct cpu_user_regs *regs,
- unsigned long cr2,
- struct x86_mem_emulator *ops,
- int mode);
+ struct x86_emulate_ctxt *ctxt,
+ struct x86_emulate_ops *ops);
/*
* Given the 'reg' portion of a ModRM byte, and a register block, return a
* pointer into the block that addresses the relevant register.
* @highbyte_regs specifies whether to decode AH,CH,DH,BH.
*/
-extern void *
+void *
decode_register(
uint8_t modrm_reg, struct cpu_user_regs *regs, int highbyte_regs);